package edu.zju.gis.cky.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import edu.zju.gis.cky.cons.Constant;
import edu.zju.gis.cky.dao.MetaMapper;
import edu.zju.gis.cky.entity.Meta;
import edu.zju.gis.cky.entity.dto.InputDTO;
import edu.zju.gis.cky.entity.dto.UpdateDTO;
import edu.zju.gis.cky.service.MetaService;
import edu.zju.gis.cky.util.CmdHelper;
import edu.zju.gis.cky.util.FileHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Zhou Yuquan
 * @version 1.0, 2021-11-17
 */
@Service
@Slf4j
public class MetaServiceImpl implements MetaService {

    @Autowired
    private MetaMapper mapper;

    @Override
    public Meta getById(long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public PageInfo<Meta> getAll(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Meta> metas = mapper.selectAll();
        return new PageInfo<>(metas);
    }

    @Override
    public PageInfo<Meta> getByGradation(int pageNum, int pageSize, String gradation) {
        PageHelper.startPage(pageNum, pageSize);
        List<Meta> metas = mapper.selectByGradation(gradation);
        return new PageInfo<>(metas);
    }

    @Override
    public void editById(UpdateDTO updateDTO) {
        mapper.updateByPrimaryKeySelective(updateDTO.toMeta());
    }

    @Override
    public void inputByType(InputDTO inputDTO) {
        String fileName = inputDTO.getFileName();
        String gradation = inputDTO.getGradation();
        String fromPath = Constant.USER_PATH + "/" + fileName;
        String toPath = Constant.DATA_PATH + "/" + gradation + "/" + fileName;

        int index = fromPath.lastIndexOf(".");
        if (fromPath.substring(index + 1).equals("shp")) {
            File fromFile = new File(fromPath);
            File fromDir = fromFile.getParentFile();
            File[] files = fromDir.listFiles();
            List<String> fromList = new ArrayList<>();
            List<String> toList = new ArrayList<>();
            for (File file : files) {
                String tempFileName = file.getName();
                if (fileName.substring(0, fileName.lastIndexOf(".")).equals(tempFileName.substring(0, tempFileName.lastIndexOf(".")))) {
                    String tempSuffix = tempFileName.substring(tempFileName.lastIndexOf(".") + 1);
                    if (Constant.SHP_FILES_SUFFIX.contains(tempSuffix)) {
                        fromList.add(file.getAbsolutePath());
                        toList.add(Constant.DATA_PATH + "/" + gradation + "/" + tempFileName);
                    }
                }
            }
            if (!FileHelper.batchCopy(fromList, toList)) {
                throw new RuntimeException("Failed to copy files.");
            }
        } else if (fromPath.substring(index + 1).equals("gdb")) {
            File fromFile = new File(fromPath);
            File[] files = fromFile.listFiles();
            List<String> fromList = new ArrayList<>();
            List<String> toList = new ArrayList<>();
            for (File file : files) {
                fromList.add(file.getAbsolutePath());
                toList.add(Constant.DATA_PATH + "/" + gradation + "/" + fromFile.getName() + "/" + file.getName());
            }
            if (!FileHelper.batchCopy(fromList, toList)) {
                throw new RuntimeException("Failed to copy files.");
            }
        } else {
            if (!FileHelper.copy(fromPath, toPath)) {
                throw new RuntimeException("Failed to copy files.");
            }
        }

        mapper.insertSelective(inputDTO.toMeta());

        if (inputDTO.getType().equals("矢量")) {
            List<String> args = new ArrayList<>();
            String suffix = fromPath.substring(index + 1);
            switch (suffix) {
                case "tsv":
                    args = Arrays.asList(
                            Constant.MODEL_PATH + "/TsvLoader.jar ",
                            Constant.PG_HOST + ":" + Constant.PG_PORT,
                            Constant.PG_DATABASE,
                            Constant.VECTOR_SCHEMA,
                            Constant.PG_USERNAME,
                            Constant.PG_PASSWORD,
                            inputDTO.getTableName(),
                            Constant.USER_PATH + "/" + inputDTO.getFileName(),
                            inputDTO.getFieldNames(),
                            inputDTO.getFieldTypes()
                    );
                    break;
                case "shp":
                    args = Arrays.asList(
                            Constant.MODEL_PATH + "/ShpPartLoader.jar ",
                            Constant.PG_HOST + ":" + Constant.PG_PORT,
                            Constant.PG_DATABASE,
                            Constant.VECTOR_SCHEMA,
                            Constant.PG_USERNAME,
                            Constant.PG_PASSWORD,
                            inputDTO.getTableName(),
                            Constant.USER_PATH + "/" + inputDTO.getFileName(),
                            inputDTO.getLayerName(),
                            Constant.LOAD_BATCH_SIZE
                    );
                    break;
                case "gdb":
                    args = Arrays.asList(
                            Constant.MODEL_PATH + "/GdbPartLoader.jar ",
                            Constant.PG_HOST + ":" + Constant.PG_PORT,
                            Constant.PG_DATABASE,
                            Constant.VECTOR_SCHEMA,
                            Constant.PG_USERNAME,
                            Constant.PG_PASSWORD,
                            inputDTO.getTableName(),
                            Constant.USER_PATH + "/" + inputDTO.getFileName(),
                            inputDTO.getLayerName(),
                            Constant.LOAD_BATCH_SIZE
                    );
                    break;
                default:
                    throw new RuntimeException("Unsupported vector type.");
            }
            String cmd = "java -jar " + String.join(" ", args);
            CmdHelper cmdHelper = new CmdHelper(cmd, false);
            cmdHelper.run();
        }
    }

    @Override
    public void outputByType(long id) {
        Meta meta = mapper.selectByPrimaryKey(id);
        String gradation = meta.getGradation();

        String fileName = meta.getStorage().substring(meta.getStorage().lastIndexOf("/") + 1);
        String fromPath = Constant.DATA_PATH + "/" + gradation + "/" + fileName;
        String toPath = Constant.USER_PATH + "/" + fileName;

        int index = fromPath.lastIndexOf(".");
        if (fromPath.substring(index + 1).equals("shp")) {
            File fromFile = new File(fromPath);
            File fromDir = fromFile.getParentFile();
            File[] files = fromDir.listFiles();
            List<String> fromList = new ArrayList<>();
            List<String> toList = new ArrayList<>();
            for (File file : files) {
                String tempFileName = file.getName();
                if (fileName.substring(0, fileName.lastIndexOf(".")).equals(tempFileName.substring(0, tempFileName.lastIndexOf(".")))) {
                    String tempSuffix = tempFileName.substring(tempFileName.lastIndexOf(".") + 1);
                    if (Constant.SHP_FILES_SUFFIX.contains(tempSuffix)) {
                        fromList.add(file.getAbsolutePath());
                        toList.add(Constant.USER_PATH + "/" + tempFileName);
                    }
                }

            }
            if (!FileHelper.batchCopy(fromList, toList)) {
                throw new RuntimeException("Failed to copy files.");
            }
        } else if (fromPath.substring(index + 1).equals("gdb")) {
            File fromFile = new File(fromPath);
            File[] files = fromFile.listFiles();
            List<String> fromList = new ArrayList<>();
            List<String> toList = new ArrayList<>();
            for (File file : files) {
                fromList.add(file.getAbsolutePath());
                toList.add(Constant.USER_PATH + "/" + fromFile.getName() + "/" + file.getName());
            }
            if (!FileHelper.batchCopy(fromList, toList)) {
                throw new RuntimeException("Failed to copy files.");
            }
        } else {
            if (!FileHelper.copy(fromPath, toPath)) {
                throw new RuntimeException("Failed to copy files.");
            }
        }
    }

}
